#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include<queue>
template <typename T>
class LockedQueue {
public:
    explicit LockedQueue() = default;
    ~LockedQueue() {
        close();
    }

public:
    // 判断是否关闭
    bool closed() {
        return __closed.load(std::memory_order_relaxed);
    }

    // 关闭
    void close() {
        if (closed()) return;
        __closed.store(true, std::memory_order_relaxed);
        __cv.notify_all();
    }

    // 获取队列大小
    std::size_t size() {
        return __size.load(std::memory_order_relaxed);
    }

    // 判断队列是否为空
    bool empty() {
        return size() == 0;
    }

public:
    // 添加元素
    void push(T val) {
        if (closed()) return;  // 判断队列是否关闭
        {
            std::lock_guard lock{__mtx};   // 加锁
            __queue.push(std::move(val));  // 添加元素
        }
        __size.fetch_add(1, std::memory_order_relaxed);  // 队列大小+1
        __cv.notify_one();                               // 通知一个线程
    }

    bool pop(T &val) {
        std::unique_lock lock{__mtx};
        __cv.wait(lock, [&]() { return !empty() || closed(); });
        if (empty()) {
            return false;
        }
        val = std::move(__queue.front());
        __queue.pop();
        __size.fetch_sub(1, std::memory_order_relaxed);
        return true;
    }

    bool try_pop(T &val) {
        if (empty()) {
            return false;
        }
        {
            std::lock_guard lock{__mtx};
            val = std::move(__queue.front());
            __queue.pop();
            __size.fetch_sub(1, std::memory_order_relaxed);
            return true;
        }
    }

private:
    std::mutex              __mtx;
    std::condition_variable __cv;
    std::queue<T>           __queue;
    std::atomic_size_t      __size{0};
    std::atomic_bool        __closed{false};
};

int main() {
    LockedQueue<int> q;

    std::thread t1([&]() {
        for (int i = 0; i < 1000000; ++i) {
            q.push(i);
        }
        q.close();
    });
    std::thread t2([&]() {
        int res;
        while (q.pop(res)) {
            std::cout << "thread1 recv :" << res << std::endl;
        }
    });
    std::thread t3([&]() {
        int res;
        while (q.pop(res)) {
            std::cout << "thread2 recv :" << res << std::endl;
        }
    });
    std::thread t4([&]() {
        int res;
        while (true) {
            if (q.try_pop(res)) {
                std::cout<<"thread3 recv "<<res<<std::endl;
            }else {
                if (q.closed()) break;
                continue;
            }
        }

    });


    t1.join();
    t2.join();
    t3.join();
    t4.join();
    return 0;
}
